package org.qdog.pk.pkscrape.controller;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.log4j.Logger;
import org.htmlcleaner.CleanerProperties;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.PrettyXmlSerializer;
import org.htmlcleaner.TagNode;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Properties;

/**
 * @since 08/2011
 */
@Component
public class UrlDownloader {
  private static final Logger LOG = Logger.getLogger(UrlDownloader.class);
  private HttpClient httpClient = new DefaultHttpClient();
  private final HtmlCleaner cleaner = new HtmlCleaner();

  private File htmlDir;
  private File xmlDir;
  private String entityDownloadUrl;

  public String convertToXml(String html) throws IOException {
    TagNode htmlRoot = cleaner.clean(html);
    CleanerProperties props = cleaner.getProperties();
    //props.setOmitComments(true);
    //props.setOmitHtmlEnvelope(true);
    //props.setPruneTags("script");
    String xml = new PrettyXmlSerializer(props).getAsString(htmlRoot);
    return xml;
  }

  private void saveToFile(String data, File directory, String filename) {
    File outFile = new File(directory, filename);
    FileOutputStream os = null;
    try {
      os = new FileOutputStream(outFile, false);
      IOUtils.write(data, os, "UTF-8");
    } catch (Exception e) {
      LOG.error("Could not save to " + outFile.getAbsolutePath(), e);
    } finally {
      try {
        os.close();
      } catch (Exception e) {
        // do nothing
      }
    }
  }

  public String downloadEntity(String id) throws IOException {
    String url = String.format(entityDownloadUrl, id);
    String html = downloadHtml(url);
    if (htmlDir != null) {
      String filename = id + ".html";
      LOG.debug("Saving html for entity " + id + " to " + filename);
      saveToFile(html, htmlDir, filename);
    }
    String xml = convertToXml(html);
    if (xmlDir != null) {
      String filename = id + ".xml";
      LOG.debug("Saving xml for entity " + id + " to " + filename);
      saveToFile(xml, xmlDir, filename);
    }
    return xml;
  }

  private String downloadHtml(String url) throws IOException {
    LOG.debug("Downloading url " + url);
    String result = null;
    HttpGet httpget = new HttpGet(url);
    HttpResponse response = httpClient.execute(httpget);
    int statusCode = response.getStatusLine().getStatusCode();
    if (statusCode >= 400) {
      LOG.error("Response http code = " + statusCode + " " + response.getStatusLine().toString());
      throw new RuntimeException("Http error");
    }
    if (statusCode == 302) {
      // redirect to error page?
      LOG.error("Response http code = " + statusCode + " " + response.getStatusLine().toString());
      throw new RuntimeException("Http error - redirect?");
    }
    HttpEntity entity = response.getEntity();
    if (entity != null) {
      result = IOUtils.toString(entity.getContent());
    }
    return result;
  }

  @Resource(name = "appProperties")
  public void setProperties(Properties properties) {
    entityDownloadUrl = properties.getProperty("entityDownloadUrl");
    boolean useProxy = new Boolean(properties.getProperty("useProxy", "false"));
    if (useProxy) {
      String proxyHost = properties.getProperty("proxyHost");
      int proxyPort = Integer.parseInt(properties.getProperty("proxyPort"));
      HttpHost proxy = new HttpHost(proxyHost, proxyPort);
      httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
    }
    boolean saveHtml = new Boolean(properties.getProperty("saveHtml", "false"));
    boolean saveXml = new Boolean(properties.getProperty("saveXml", "false"));
    String docSaveDirectory = properties.getProperty("docSaveDirectory", ".");
    if (saveHtml || saveXml) {
      File base = new File(docSaveDirectory);
      if (saveHtml) {
        htmlDir = new File(base, "html");
        if (!htmlDir.isDirectory()) {
          htmlDir.mkdirs();
        }
      }
      if (saveXml) {
        xmlDir = new File(base, "xml");
        if (!xmlDir.isDirectory()) {
          xmlDir.mkdirs();
        }
      }
    }
  }

}
